package com.flyan.game.motafx.component.terrain;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import com.almasb.fxgl.core.util.LazyValue;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.component.Component;
import com.almasb.fxgl.physics.BoundingShape;
import com.almasb.fxgl.physics.HitBox;
import com.almasb.fxgl.texture.AnimatedTexture;
import com.almasb.fxgl.texture.AnimationChannel;
import com.flyan.game.motafx.config.GameConfig;
import com.flyan.game.motafx.core.enums.EntityTypeEnum;
import com.flyan.game.motafx.core.util.animate.StillAnimateTable;
import com.flyan.game.motafx.core.util.entity.EntityUtils;
import com.flyan.game.motafx.core.util.sound.SoundUtils;
import com.flyan.game.motafx.effect.BaseEffect;
import com.flyan.game.motafx.entity.terrain.TerrainEntityInfo;
import javafx.util.Duration;

/**
 * 地形组价
 *
 * @author flyan
 * @version 1.0
 * @email flyan_by_chenu@sina.com
 * @since 2025/1/31
 */
public class TerrainComponent extends Component {

    private AnimatedTexture atView;
    private int destroyAnimateCode = -1;
    private String destroySoundName;

    private CollisionIsCanDestroyPredicate collisionIsCanDestroyPredicate;
    private collisionDestroyConsumer collisionDestroyConsumer;

    /**
     * 地形动画
     */
    private LazyValue<StillAnimateTable> animateTable = new LazyValue<>(() -> new StillAnimateTable(
            FXGL.image("materials/terrains.png"), GameConfig.GRID_SIZE, GameConfig.GRID_SIZE));
    /**
     * 地形破坏动画
     */
    private LazyValue<StillAnimateTable> destroyAnimateTable = new LazyValue<>(() -> new StillAnimateTable(
            FXGL.image("materials/animates.png"), 4,
            GameConfig.GRID_SIZE, GameConfig.GRID_SIZE, Duration.seconds(0.3)));

    public TerrainComponent() {

    }

    public TerrainComponent setDestroyAnimateCode(int destroyAnimateCode) {
        this.destroyAnimateCode = destroyAnimateCode;
        return this;
    }

    public TerrainComponent setDestroySoundName(String destroySoundName) {
        this.destroySoundName = destroySoundName;
        return this;
    }

    public TerrainComponent setCollisionIsCanDestroyPredicate(CollisionIsCanDestroyPredicate collisionIsCanDestroyPredicate) {
        this.collisionIsCanDestroyPredicate = collisionIsCanDestroyPredicate;
        return this;
    }

    public TerrainComponent setCollisionDestroyConsumer(TerrainComponent.collisionDestroyConsumer collisionDestroyConsumer) {
        this.collisionDestroyConsumer = collisionDestroyConsumer;
        return this;
    }

    @Override
    public void onAdded() {
        /* 根据地形类型渲染动画 */
        EntityTypeEnum type = (EntityTypeEnum) entity.getType();
        if (type.getType() >= 0) {
            atView = new AnimatedTexture(animateTable.get().get(type.getType()));

            /* 挂载并播放动画 */
            entity.getViewComponent().addChild(atView);
            entity.getBoundingBoxComponent().addHitBox(new HitBox(BoundingShape.box(
                    GameConfig.GRID_BBOX_SIZE, GameConfig.GRID_BBOX_SIZE)));
            entity.setEverUpdated(true);
            atView.loop();
        }
    }

    /**
     * 碰撞是否可破坏
     *
     * @param other
     * @return
     */
    public boolean collisionIsCanDestroy(Entity other) {
        TerrainEntityInfo info = EntityUtils.getEntityInfo(entity, TerrainEntityInfo.class);
        if (!info.isCanDestroy()) {
            return false;
        }

        /* 该实体是否可碰撞破坏当前实体 */
        if (collisionIsCanDestroyPredicate != null) {
            return collisionIsCanDestroyPredicate.collisionIsCanDestroy(other);
        }

        /* 未设置默认不可破坏 */
        return false;
    }

    /**
     * 碰撞开始
     *
     * @param other 碰到到物品的其他实体
     */
    public void onCollisionBegin(Entity other) {
        TerrainEntityInfo terrainInfo = EntityUtils.getEntityInfo(entity, TerrainEntityInfo.class);
        /* 触发地形效果 */
        if (CollUtil.isNotEmpty(terrainInfo.getEffects())) {
            terrainInfo.getEffects().forEach(it -> {
                BaseEffect effect = ReflectUtil.newInstance(it);
                effect.setTriggerEntity(entity);
                effect.apply(other);
            });
        }
        /* 可破坏 */
        if (collisionIsCanDestroy(other)) {
            /* 设置破坏动画 */
            if (destroyAnimateCode != -1) {
                AnimationChannel animationChannel = destroyAnimateTable.get().get(destroyAnimateCode);
                atView.playAnimationChannel(animationChannel);
            }
            if (destroySoundName != null) {
                SoundUtils.play(destroySoundName);
            }
            if (collisionDestroyConsumer != null) {
                collisionDestroyConsumer.collisionDestroy(other);
            }
            FXGL.runOnce(() -> entity.removeFromWorld(), Duration.seconds(0.35));
        }
    }

    @FunctionalInterface
    public interface CollisionIsCanDestroyPredicate {
        boolean collisionIsCanDestroy(Entity other);
    }

    @FunctionalInterface
    public interface collisionDestroyConsumer {
        void collisionDestroy(Entity other);
    }

}
